/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.mzk.kramerius.articles.importFromLn.articlesData.pesta;

import cz.mzk.kramerius.articles.importFromLn.PropertyNames;
import cz.mzk.kramerius.articles.importFromLn.articlesData.ArticleComponents;
import cz.mzk.kramerius.articles.importFromLn.articlesData.ArticleComponentsCreator;
import cz.mzk.kramerius.articles.importFromLn.articlesData.CsvParser;
import cz.mzk.kramerius.articles.importFromLn.articlesData.ErroneousArticle;
import cz.mzk.kramerius.articles.importFromLn.articlesData.jiranova.ArticleBuilder;
import cz.mzk.kramerius.articles.importFromLn.articlesData.jiranova.ErroneousArticleImpl;
import cz.mzk.kramerius.articles.importFromLn.articlesData.jiranova.Requirements;
import cz.mzk.kramerius.articles.importFromLn.domain.Article;
import cz.mzk.kramerius.articles.importFromLn.domain.Genre;
import cz.mzk.kramerius.commons.PropertyLoader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author x211800
 */
public class PestaCsvParser1 extends CsvParser {

    private static final String MY_OK_ARTICLES_FILE = "Parser.myOkArticlesFile";
    private static final String MY_ERR_ARTICLES_FILE = "Parser.myErrArticlesFile";
    private static final String SEC_PART_ARTICLES_FILE = "Parser.secondPart";
    private static final String ORIGIN_ARTICLES_FILE = "Parser.originArticlesFile";
    private static final char WHITESPACE = ' ';
    private static final Logger logger = Logger.getLogger(PestaCsvParser1.class.getName());
    private static final char CSV_FIELD_SEPARATOR = '\t';
    private static final char CSV_TEXT_SEPARATOR = '\"';
    private Properties properties;
    private final Requirements requirements;
    private final File inputFile;
    private final File erroneousArticlesFile;
    private final File myOkArticlesFile;
    private final File myErroneousArticlesFile;
    private final File originArticlesFile;
    private final File secondPartOfImportingFile;
    private final List<Article> correctArticles = new ArrayList<Article>();
    private final List<ErroneousArticle> erroneousArticles = new ArrayList<ErroneousArticle>();
    List<String> okArticles = new ArrayList<String>();
    Map<Integer, String> errArticles = new HashMap<Integer, String>();
    private boolean forChildren;
    protected static final String SEMICOLON = ";";
    private List<String> secondPart = new ArrayList<String>();

    public PestaCsvParser1(Properties properties) {
        this.properties = properties;
        requirements = new Requirements(properties);
        PropertyLoader loader = new PropertyLoader(properties);

        inputFile = loader.loadFile(PropertyNames.PARSER_INPUT_FILE, true, true, false);
        erroneousArticlesFile = loader.loadFile(PropertyNames.PARSER_ERR_ARTICLES_FILE, false, false, false);

        myOkArticlesFile = loader.loadFile(MY_OK_ARTICLES_FILE, false, false, false);
        myErroneousArticlesFile = loader.loadFile(MY_ERR_ARTICLES_FILE, false, false, false);
        originArticlesFile = loader.loadFile(ORIGIN_ARTICLES_FILE, false, false, false);
        secondPartOfImportingFile = loader.loadFile(SEC_PART_ARTICLES_FILE, false, false, false);

    }

    @Override
    public List<Article> getCorrectArticles() {
        return correctArticles;
    }

    public List<ErroneousArticle> getErroneousArticles() {
        return erroneousArticles;
    }

    @Override
    public void parseArticles() {
        try {
            LineNumberReader reader = new LineNumberReader(new FileReader(inputFile));
            int lineNumber = 0;
            ArticleBuilder articleBuilder = null;
            int okInt = 0;
            int notOkInt = 0;


            while (reader.ready()) {
                boolean ok = true;
                String errOutput = null;
                Genre genre = null;
                String name = null;
                String date = null;
                String volumeNumber = null;
                String dayTimes = null;
                StringBuffer noteBuffer = new StringBuffer("");
                String issues = null;
                String pages = null;
                forChildren = false;

                String line = reader.readLine();

                if (lineNumber == 0) {
                    //vynechani prvniho radku s hlavickou
                    lineNumber++;
                    continue;
                }

                String[] columns = line.split(String.valueOf(CSV_FIELD_SEPARATOR));


                if (columns.length > 1) {
                    try {

                        //detection LN or LND string in columns[5]
                        columns = isLND(columns);

                        //parse genre - columns[0]
                        ColumnOfGenre columnOfGenre = ColumnOfGenre.instanceOf(columns[0]);
                        genre = columnOfGenre.getParsedGenre();

                        //parse authors - columns[1]
                        ColumnOfAuthors columnOfAuthors = ColumnOfAuthors.instanceOf(columns[1]);
                        name = columnOfAuthors.getParsedAuthors();

                        //parse dates and number of volume - columns[5]
                        ColumnOfDates columnOfDates = ColumnOfDates.instanceOf(columns[5]);
                        int countOfDates = columnOfDates.getCountOfDates();
                        date = columnOfDates.getParsedDates();
                        volumeNumber = columnOfDates.getVolumeNumber();

                        //parse numbers of issues and daytimes - columns[6]
                        ColumnOfIssues columnOfIssues = ColumnOfIssues.instanceOf(columns[6]);
                        issues = columnOfIssues.getParsedIssues();
                        int countOfIssues = columnOfIssues.getCountOfIssues();
                        int countOfDayTimes = columnOfIssues.getCountOfDayTimes();
                        dayTimes = columnOfIssues.getDayTimes();
                        noteBuffer = columnOfIssues.getNote();

                        //parse pages and additional notes - columns[7]
                        ColumnOfPages columnOfPages = ColumnOfPages.instanceOf(columns[7]);
                        pages = columnOfPages.getParsedPages();
                        int countOfScalePages = columnOfPages.getCountOfScalePages();
                        if (noteBuffer.length() < 1) {
                            noteBuffer = columnOfPages.getNote();
                        } else {
                            noteBuffer.append(SEMICOLON);
                            noteBuffer.append(columnOfPages.getNote().toString());
                        }
                        //checking
                        isSame(countOfDates, countOfScalePages, countOfIssues, countOfDayTimes);

                    } catch (Exception e) {
                        errOutput = "exception: " + e.getMessage();
                        ok = false;
                    }



                    if (ok) {

                        ColumnOfNote columnOfnote = ColumnOfNote.instanceOf(columns, noteBuffer.toString());
                        String note = columnOfnote.getNote();

                        okInt++;
                        okArticles.add(
                                addTextDelimits(String.valueOf(lineNumber)) + CSV_FIELD_SEPARATOR
                                + addTextDelimits(genre.myToString()) + CSV_FIELD_SEPARATOR
                                + addTextDelimits(name) + CSV_FIELD_SEPARATOR
                                + (columns[2]) + CSV_FIELD_SEPARATOR
                                + (columns[3]) + CSV_FIELD_SEPARATOR
                                + addTextDelimits(note) + CSV_FIELD_SEPARATOR
                                + addTextDelimits(date) + CSV_FIELD_SEPARATOR
                                + addTextDelimits(volumeNumber) + CSV_FIELD_SEPARATOR
                                + addTextDelimits(issues) + CSV_FIELD_SEPARATOR
                                + addTextDelimits(dayTimes.toString()) + CSV_FIELD_SEPARATOR
                                + addTextDelimits(pages) + CSV_FIELD_SEPARATOR);


                        articleBuilder = createArticleBuilder(genre, name, removeTextDelimits(columns[2]), removeTextDelimits(columns[3]), note, lineNumber);
                        articleBuilder.addArticleComponents(createArticleComponents(volumeNumber, date, issues, dayTimes, pages, lineNumber));

                        if (articleBuilder.hasErrors()) {
                            ErroneousArticleImpl errArticle = new ErroneousArticleImpl();
                            errArticle.setInputData(
                                    new String[]{
                                        addTextDelimits(String.valueOf(lineNumber)),
                                        columns[0],
                                        addTextDelimits("cze"),
                                        addTextDelimits(name),
                                        (columns[2]),
                                        (columns[3]),
                                        addTextDelimits(note),
                                        addTextDelimits(volumeNumber),
                                        addTextDelimits(date),
                                        addTextDelimits(issues),
                                        addTextDelimits(dayTimes.toString()),
                                        addTextDelimits(pages)});

                            errArticle.setErrorMessages(articleBuilder.getErrorMessages());

                            erroneousArticles.add(errArticle);
                            secondPart.add(line);

                        } else {
                            correctArticles.add(articleBuilder.getArticle());
                        }


                    } else {
                        notOkInt++;
                        errArticles.put(lineNumber, errOutput);
                    }
                    lineNumber++;
                }
            }
            writeOkArcticles();
            mySaveErroneousArticles();
            System.out.println(okInt);
            System.out.println(notOkInt);

        } catch (FileNotFoundException ex) {
            Logger.getLogger(PestaCsvParser1.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(PestaCsvParser1.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    ArticleBuilder createArticleBuilder(Genre genre, String author, String title, String subtitle, String info, int articleId) {
        ArticleBuilder articleBuilder = new ArticleBuilder(articleId, requirements);
        articleBuilder.setGenre(genre);
        articleBuilder.processLanguage("cze");
        articleBuilder.processAuthor(author);
        articleBuilder.processTitle(title);
        articleBuilder.procesSubtitle(subtitle);
        articleBuilder.procesInfo(info);
        //TODO: pouzit note ve foxml

        return articleBuilder;
    }

    public ArticleComponents createArticleComponents(String volumeNumber, String date, String issues, String dayTimes, String pages, int id) {

        ArticleComponentsCreator acc = new cz.mzk.kramerius.articles.importFromLn.articlesData.pesta.SingleVolumeACCreator(properties, volumeNumber, date, issues, dayTimes.toString(), pages, id, forChildren);

        ArticleComponents components = new ArticleComponents();
        components.setComponents(acc.getArticleComponents());
        components.setError(acc.getError());
        return components;
    }

    public void mySaveErroneousArticles() {
        try {
            LineNumberReader originReader = new LineNumberReader(new FileReader(originArticlesFile));
            FileWriter writer = new FileWriter(myErroneousArticlesFile);
            int localLineNumber = 0;





            while (originReader.ready()) {
                String line = originReader.readLine();
                if (localLineNumber == 0) {
                    //vynechani prvniho radku
                    localLineNumber++;
                    continue;
                }

                if (localLineNumber != 1 && errArticles.keySet().contains(localLineNumber)) {
                    writer.write(addTextDelimits(String.valueOf(localLineNumber)));
                    writer.write(CSV_FIELD_SEPARATOR);
                    writer.write(line);
                    writer.write(CSV_FIELD_SEPARATOR);
                    writer.write(addTextDelimits(errArticles.get(localLineNumber)));
                    writer.write("\n");

                }

                localLineNumber++;
            }

            originReader.close();
            writer.close();


        } catch (IOException ex) {
            logger.log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public boolean hasErroneousArticles() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void printStatistics(PrintStream out) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    private void writeOkArcticles() {
        try {
            FileWriter writer = new FileWriter(myOkArticlesFile);
            for (String line : okArticles) {
                writer.write(line);
                writer.write("\n");
            }
            writer.close();

        } catch (IOException ex) {
            logger.log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void saveErroneousArticles() {
        try {
            FileWriter writer = new FileWriter(erroneousArticlesFile);
            String header = createHeaderLine();
            writer.write(header);
            for (ErroneousArticle article : erroneousArticles) {
                String line = article.toString();//createCsvLine(article);
                writer.write(line);
                writer.write("\n");
            }


            FileWriter secondPartOfImportingWriter = new FileWriter(secondPartOfImportingFile);
            for (String line : secondPart) {
                secondPartOfImportingWriter.write(line);
                secondPartOfImportingWriter.write("\n");
            }

            secondPartOfImportingWriter.close();
            writer.close();
            logger.log(Level.INFO, "Erroneous articles ({0}) saved to file ''{1}''", new Object[]{Integer.valueOf(erroneousArticles.size()), erroneousArticlesFile.getAbsoluteFile()});
        } catch (IOException ex) {
            logger.log(Level.SEVERE, null, ex);
        }
    }

    private String[] isLND(String[] c) throws ColumnsError {
        String[] columns = c;

        if (columns.length > 5) {
            if (removeTextDelimits(columns[5]).equals("LND")) {
                forChildren = true;
            }
//                if (!removeTextDelimits(columns[5]).equals("LN")) {
//                throw new ColumnsError("LN/LND column problem" + col);
//            }
            if ((removeTextDelimits(columns[5]).equals("LND")) || (removeTextDelimits(columns[5]).equals("LN"))) {
                for (int i = 6; i < columns.length; i++) {
                    columns[i - 1] = columns[i];
                }
                columns[columns.length - 1] = null;
            }
        }
        return columns;
    }

    private void isSame(int countOfDates, int countOfScalePages, int countOfIssues, int countOfDayTimes) throws ColumnsError {
        if (!(countOfDates == countOfScalePages && countOfIssues == countOfDates
                && countOfDayTimes == countOfDates)) {
            throw new ColumnsError(
                    "counters doesn't equal countOfDates: " + countOfDates
                    + " countOfScalePages: " + countOfScalePages
                    + " countOfIssues: " + countOfIssues
                    + " countOfDayTimes " + countOfDayTimes);
        }
    }
}
